package com.hengpeng.itfin.service.repayment.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.annotations.common.util.StringHelper;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.hengpeng.common.exception.ServiceResult;
import com.hengpeng.common.exception.ServiceResultFactory;
import com.hengpeng.common.persist.query.DynamicQuery;
import com.hengpeng.common.persist.query.Projections;
import com.hengpeng.common.persist.query.constants.QueryConstants.QueryType;
import com.hengpeng.common.util.DateTimeUtil;
import com.hengpeng.common.util.MoneyUtil;
import com.hengpeng.itfin.constants.MSConstants;
import com.hengpeng.itfin.service.impl.BaseServiceImpl;
import com.hengpeng.itfin.service.repayment.RepaymentService;
import com.hengpeng.itfin.tools.New;
import com.hengpeng.itfin.tools.PoolServer;
import com.hengpeng.itfinbase.constants.RespCodeConstants;
import com.hengpeng.itfinbase.constants.RespCodeConstants.CommonCode;
import com.hengpeng.itfinbase.constants.TransCodeConstants;
import com.hengpeng.itfinbase.en.BorrowStatus;
import com.hengpeng.itfinbase.en.InvestStatus;
import com.hengpeng.itfinbase.en.TradeMode;
import com.hengpeng.itfinbase.en.TransType;
import com.hengpeng.itfinbase.message.partner.PartnerTransType;
import com.hengpeng.itfinbase.message.partner.ReconciliationRequestMsg;
import com.hengpeng.itfinbase.message.partner.ReconciliationResponseMsg;
import com.hengpeng.itfinbase.message.partner.ReconciliationResponseMsg.ReconciliationInfo;
import com.hengpeng.itfinbase.message.partner.RepaymentRequestMsg;
import com.hengpeng.itfinbase.message.partner.RepaymentResponseMsg;
import com.hengpeng.itfinbase.message.partner.RepaymentResponseMsg.RepaymentResponseErrorMsg;
import com.hengpeng.itfinbase.message.partner.TransferResponse;
import com.hengpeng.itfinbase.message.partner.TrfReconciliationRequestMsg;
import com.hengpeng.itfinbase.message.partner.TrfReconciliationResponseMsg;
import com.hengpeng.itfinbase.message.partner.TrfReconciliationResponseMsg.TrfReconciliationDto;
import com.hengpeng.itfinbase.persist.Account;
import com.hengpeng.itfinbase.persist.AccountLog;
import com.hengpeng.itfinbase.persist.BorrowInfo;
import com.hengpeng.itfinbase.persist.InvestInfo;
import com.hengpeng.itfinbase.persist.MessageTemplates;
import com.hengpeng.itfinbase.persist.ReceivePlan;
import com.hengpeng.itfinbase.persist.ReceivePlan.ReceiveStatus;
import com.hengpeng.itfinbase.persist.RecoverRepay;
import com.hengpeng.itfinbase.persist.RecoverRepay.RecoverRepayStatus;
import com.hengpeng.itfinbase.persist.RepaymentPlan;
import com.hengpeng.itfinbase.persist.RepaymentPlan.ReplaymentStatus;
import com.hengpeng.itfinbase.persist.RepaymentPlan.ReplaymentType;
import com.hengpeng.itfinbase.persist.SystemLog.LogType;

@Lazy
@Service
public class RepaymentServiceImpl extends BaseServiceImpl implements RepaymentService {

    @Override
    public boolean checkRepaymentPlanIsRepaymented(Long borrowInfoId, Integer curRecNum) {
        DynamicQuery query = new DynamicQuery(ReceivePlan.class);
        query.addProjection(Projections.count("id"));
        if (borrowInfoId != null) {
            query.eq("borrowInfoId", borrowInfoId);
        }
        if (curRecNum != null) {
            query.eq("curRecNum", curRecNum);
        }
        query.inArray("status", new ReceiveStatus[] { ReceiveStatus.WAITREC, ReceiveStatus.RECEIVING });
        query.setQueryType(QueryType.JDBC);
        Long size = serviceFactory.getDaoFactory().getReceivePlanDao().countByDynamicQuery(query);
        return size > 0 ? false : true;
    }

    @Override
    public boolean checkBorrowInfoIsRepaymented(Long borrowInfoId) {
        DynamicQuery query = new DynamicQuery(RepaymentPlan.class);
        query.addProjection(Projections.count("id"));
        if (borrowInfoId != null) {
            query.eq("borrowinfoId", borrowInfoId);
        }
        query.inArray("status", new ReplaymentStatus[] { ReplaymentStatus.UNSETTLE, ReplaymentStatus.SETTLING });
        query.setQueryType(QueryType.JDBC);
        Long size = serviceFactory.getDaoFactory().getRepaymentPlanDao().countByDynamicQuery(query);
        return size > 0 ? false : true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateReceivePlanStatus(Long id, ReceiveStatus newStatus, ReceiveStatus oldStatus, Date receiveTime,
            Date updateTime) {
        return serviceFactory.getDaoFactory().getReceivePlanDao()
                .updateStatus(id, ReceiveStatus.RECEIVED, ReceiveStatus.RECEIVING, new Date(), new Date());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 120)
    public int[] batchUpdateReceivePlanStatus(List<String> ids, ReceiveStatus newStatus, ReceiveStatus oldStatus,
            Date receiveTime, Date updateTime) {
        return serviceFactory.getDaoFactory().getReceivePlanDao()
                .batchUpdateStatus(ids, ReceiveStatus.RECEIVED, ReceiveStatus.RECEIVING, new Date(), new Date());
    }

    /**
     * <pre>
     * 程序执行步骤：
     * 一,对于返回的结果中成功的部分执行如下操作：
     * 				(1)更新对应的收款计划中收款状态为：已收款 
     * 				(2)生成还款人的还款资金流水,资金流水中的金额就是成功部分的金额总计. 
     * 				(3)生成收款人的收款资金流水
     * 		    (4)更新借款人资金账户表中可用余额,待还本金,待还利息字段信息,更新收款人资金账户表中可用余额,累计收益金额,待收本金,待收收益字段信息。 
     * 二,成功的部分执行完成之后,判断本期还款计划对应的收款计划是否已经都还清,如果都还清则更新本期还款计划状态为：已还清。
     * 三,步骤二执行完成之后,判断借款人的所有还款计划是否已经全部还清，若已经全部还清则更新借款标的状态为：已还清。
     * 四,当还款为平台垫资还款时需生成追偿信息表
     * </pre>
     */
    @Override
    public ServiceResult<String> dealBatchRepaymentResult(RepaymentResponseMsg response) {
        String batchId = response.getBatchId();// 还款批次id
        String proId = response.getProId();// 借款标的id
        BorrowInfo borrowInfo = daoFactory.getBorrowInfoDao().get(Long.parseLong(proId));// 获取标的信息
        if (borrowInfo == null) {
            serviceFactory.getSystemLogService().addLog("", response.getOrdId(), LogType.SYSTEMERROR,
                    "标的信息不存在,汇付返回订单号[" + response.getOrdId() + "]");
            return ServiceResultFactory.getServiceResult(RespCodeConstants.CommonCode.TRANS_FAIL, null, "标的信息不存在");
        } else if (borrowInfo.getStatus() != BorrowStatus.REPAYMENTING) {
            serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(), response.getOrdId(),
                    LogType.REPAYMENT_EXCEPTION, "标的信息状态异常，当前标的状态：" + borrowInfo.getStatus());
            return ServiceResultFactory.getServiceResult(RespCodeConstants.CommonCode.TRANS_FAIL, null, "标的信息状态异常");
        }

        RepaymentPlan repaymentPlan = daoFactory.getRepaymentPlanDao().get(response.getRepaymentPlanId());
        if (!ReplaymentStatus.UNSETTLE.equals(repaymentPlan.getStatus())
                && !ReplaymentStatus.SETTLING.equals(repaymentPlan.getStatus())) {
            serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(), response.getOrdId(),
                    LogType.REPAYMENT_EXCEPTION, "该笔还款计划已经还完:" + response.getRepaymentPlanId());
            return ServiceResultFactory.getServiceResult(RespCodeConstants.CommonCode.TRANS_FAIL, null, "该笔还款计划已经还完:"
                    + response.getRepaymentPlanId());
        }

        List<String> errorIds = New.list();// 执行失败的还款订单号
        List<RepaymentResponseErrorMsg> errorMsg = response.getRepaymentErrorMsg();
        if (errorMsg != null && errorMsg.size() > 0) {
            for (RepaymentResponseErrorMsg m : errorMsg) {
                errorIds.add(m.getOrdId());
            }
        }
        Long repayMoney = 0L;// 借款人应还金额
        Long recInterestMoney = 0L; // 借款人应还利息
        Long base = 0L;// 借款人应还本金
        Integer curRecNum = null;// 本批次处理的还款计划期数
        List<ReceivePlan> receivePlans = daoFactory.getReceivePlanDao().getRepayReceivePlans(Long.parseLong(proId),
                batchId, null, new ReceiveStatus[] { ReceiveStatus.RECEIVING });

        if (receivePlans != null && receivePlans.size() > 0) {
            List<String> receivePlanIds_list = New.list();// 收款成功的收款计划idList
            List<String> investUserId_list = New.list();// 收款成功的投标人idList
            for (int i = 0; i < receivePlans.size(); i++) {
                if (!errorIds.contains(receivePlans.get(i).getId().toString())) {
                    investUserId_list.add(receivePlans.get(i).getInvestUserId().toString());
                    receivePlanIds_list.add(receivePlans.get(i).getId().toString());
                }
            }
            if (receivePlanIds_list.size() > 0) {
                int[] i = serviceFactory.getRepaymentService().batchUpdateReceivePlanStatus(receivePlanIds_list,
                        ReceiveStatus.RECEIVED, ReceiveStatus.RECEIVING, new Date(), new Date());
                if (i != null && i.length == receivePlanIds_list.size()) {
                    Long[] investUserId_long = new Long[investUserId_list.size()];
                    for (int j = 0; j < investUserId_list.size(); j++) {
                        investUserId_long[j] = Long.parseLong(investUserId_list.get(j));
                    }
                    List<Account> accounts = serviceFactory.getAccountService().getAccounts(investUserId_long);
                    List<AccountLog> accountLogs = New.list();
                    for (Account account : accounts) {
                        for (ReceivePlan r : receivePlans) {
                            curRecNum = r.getCurRecNum();
                            if (account.getUserId().equals(r.getInvestUserId())) {
                                Long beforeBaseMoney = account.getBaseMoney();// 交易前本金
                                account.setBaseMoney(account.getBaseMoney() + r.getRecMoney());
                                account.setTotalIncomeMoney(account.getTotalIncomeMoney() + r.getRecInterestMoney()
                                        + r.getRecAddMoney());
                                account.setBaseMoneyCollect(account.getBaseMoneyCollect() - r.getRecBaseMoney());
                                account.setInComeMoneyCollect(account.getInComeMoneyCollect() - r.getRecInterestMoney()
                                        - r.getRecAddMoney());
                                AccountLog accountLog = new AccountLog();
                                accountLog.setUserId(account.getUserId());
                                accountLog.setUserName(account.getUserName());
                                accountLog.setTrustAccountId(account.getTrustAccountId());
                                accountLog.setTransType(TransType.REPAYMENT);
                                accountLog.setAccountType(account.getAccountType());
                                accountLog.setReferenceId(r.getId().toString());
                                accountLog.setMoney(r.getRecMoney());
                                accountLog.setTransTime(new Date());
                                accountLog.setTradeMode(TradeMode.ADD);
                                accountLog.setCreateTime(new Date());
                                accountLog.setUpdateTime(new Date());
                                accountLog.setBaseMoney(beforeBaseMoney);// 交易前本金
                                accountLog.setRemnantBaseMoney(account.getBaseMoney());// 交易后本金
                                accountLog.setRemnantFreezeMoney(account.getFreezeMoney());// 交易后冻结资金
                                accountLog.setRemark("收回本金 :" + r.getRecBaseMoney() / 100 + ",收回利息："
                                        + r.getRecInterestMoney() / 100 + ",收回附加利息： "
                                        + (r.getRecAddMoney() > 0 ? r.getRecAddMoney() / 100 : 0));
                                accountLogs.add(accountLog);
                                repayMoney = repayMoney + r.getRecBaseMoney() + r.getRecInterestMoney()
                                        + r.getRecAddMoney();
                                recInterestMoney = recInterestMoney + r.getRecInterestMoney();
                                base = base + r.getRecBaseMoney();

                                // 站内信 还款
                                Map<String, Object> map = new HashMap<String, Object>();
                                map.put("date", new Date());
                                map.put("money", MoneyUtil.convertFenToYuan(r.getRecMoney()));
                                serviceFactory.getMessageService().asynsendSystemMessageByTypeWithUsrCustId(
                                        r.getInvestUserTrustAccountId(), MessageTemplates.BusiType.M510.name(), map);
                            }
                        }
                    }
                    serviceFactory.getPersistService().updateAllObject(accounts);
                    serviceFactory.getPersistService().saveAllObject(accountLogs);

                } else {
                    serviceFactory.getSystemLogService().addLog(
                            borrowInfo.getId().toString(),
                            repaymentPlan.getId().toString(),
                            LogType.REPAYMENT_EXCEPTION,
                            "更新收款计划报错，应该更新条数：[" + receivePlanIds_list.size() + "],实际更新条数[" + (i == null ? 0 : i.length)
                                    + "]");
                    throw new RuntimeException("更新收款计划报错");
                }

                // 还款人资金账户变动,资金流水添加
                if (repayMoney > 0) {
                    if (MSConstants.CHAR_ONE.equals(response.getMerPriv())) {// 担保公司垫资还款,记录担保用户账户资金变动
                        serviceFactory.getAccountService().changeAccountMoney(borrowInfo.getGuaranteeUserId(),
                                repayMoney, 0l, 0l, 0l, TransType.ADVANCEREPAY, TradeMode.SUBTRACT,
                                borrowInfo.getId().toString(), "担保人垫资本息| 标的:" + borrowInfo.getBorrowName());
                        // changeAccountMoney(borrowInfo.getGuaranteeUserId(),
                        // repayMoney, TransType.ADVANCEREPAY,
                        // TradeMode.SUBTRACT, borrowInfo.getId().toString(),
                        // "担保人垫资本息| 标的:" + borrowInfo.getBorrowName());
                    } else {// 借款人正常还款
                        serviceFactory.getAccountService().changeAccountMoney(borrowInfo.getBorrowUserId(), repayMoney,
                                base, repaymentPlan.getRepayInterestMoney(), 0l, TransType.REPAYMENT,
                                TradeMode.SUBTRACT, borrowInfo.getId().toString(),
                                "融资还款|标的:" + borrowInfo.getBorrowName());
                        // changeAccountMoney(borrowInfo.getBorrowUserId(),
                        // repayMoney,
                        // base, repaymentPlan.getRepayInterestMoney(),
                        // TransType.REPAYMENT, TradeMode.SUBTRACT,
                        // borrowInfo.getId().toString(), "融资还款|标的:" +
                        // borrowInfo.getBorrowName());
                    }
                }
                /**
                 * 判断本期还款计划对应的收款计划是否已经都还清,如果都还清则更新本期还款计划状态为：已还清。
                 */
                boolean isRepaymentPlanRepaymented = serviceFactory.getRepaymentService()
                        .checkRepaymentPlanIsRepaymented(Long.parseLong(proId), curRecNum);
                if (isRepaymentPlanRepaymented) {
                    int m = serviceFactory.getRepaymentService().updateRepaymentPlanStatus(Long.parseLong(proId),
                            ReplaymentStatus.REPAYMENTED, ReplaymentStatus.SETTLING, new Date(), new Date(), curRecNum);
                    if (m > 0) {
                        serviceFactory.getSystemLogService().addLog(proId, repaymentPlan.getId().toString(),
                                LogType.REPAYMENT_MESSAGE, "更新本期还款计划成功，期数[" + curRecNum + "]");
                    } else {
                        serviceFactory.getSystemLogService().addLog(proId, repaymentPlan.getId().toString(),
                                LogType.REPAYMENT_EXCEPTION, "更新本期还款计划失败，期数[" + curRecNum + "]");
                    }
                }
                /**
                 * 判断借款人的所有还款计划是否已经全部还清，若已经全部还清则更新借款标的状态为：已还清。
                 */
                boolean isBorrowInfoRepaymented = serviceFactory.getRepaymentService().checkBorrowInfoIsRepaymented(
                        Long.parseLong(proId));
                if (isBorrowInfoRepaymented) {
                    // 更新标的状态为已还清
                    int n = serviceFactory.getBorrowService().updateBorroInoStatus(Long.parseLong(proId),
                            BorrowStatus.REPAYMENTED, BorrowStatus.REPAYMENTING, new Date(), new Date());
                    if (n > 0) {
                        serviceFactory.getSystemLogService().addLog(proId, repaymentPlan.getId().toString(),
                                LogType.REPAYMENT_MESSAGE, "更新标的状态成功");
                    } else {
                        serviceFactory.getSystemLogService().addLog(proId, repaymentPlan.getId().toString(),
                                LogType.REPAYMENT_EXCEPTION, "更新标的状态失败");
                    }

                    // 同时将该借款标的对应的投资信息记录状态改变为：已回款
                    int j = serviceFactory.getInvestInfoService().updateAllInvestInfoStatus(borrowInfo.getId(),
                            InvestStatus.LOANED, InvestStatus.RETURNED);
                    if (j > 0) {
                        serviceFactory.getSystemLogService().addLog(proId, proId, LogType.REPAYMENT_MESSAGE,
                                "更新借款标的对应的投资信息记录状态改变为：已回款,成功，标的ID[" + proId + "],更新数量[" + j + "]");
                    } else {
                        serviceFactory.getSystemLogService().addLog(proId, proId, LogType.REPAYMENT_EXCEPTION,
                                "更新借款标的对应的投资信息记录状态改变为：已回款,失败");
                    }
                }
                /**
                 * 如果是平台垫资还款则添加追偿信息
                 */
                if (MSConstants.CHAR_ONE.equals(response.getMerPriv())) {
                    if (repayMoney > 0) {
                        saveRecoverRepayInfo(repaymentPlan, repayMoney, repaymentPlan.getRepayBaseMoney(),
                                repaymentPlan.getRepayInterestMoney());
                    }
                }
            }
        }
        return ServiceResultFactory.getServiceResult(CommonCode.TRANS_SUC, String.class);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateRepaymentPlanStatus(Long borrowInfoId, ReplaymentStatus newStatus, ReplaymentStatus oldStatus,
            Date repayTime, Date updateTime, int curRecNum) {
        return serviceFactory
                .getDaoFactory()
                .getRepaymentPlanDao()
                .updateStatus(borrowInfoId, ReplaymentStatus.REPAYMENTED, ReplaymentStatus.SETTLING, repayTime,
                        updateTime, curRecNum);
    }

    /**
     * 保存垫资信息
     * 
     * @param plan
     * @param repaymoney
     * @param totalRepayBaseMoney
     * @param interest
     */
    private void saveRecoverRepayInfo(RepaymentPlan plan, Long repaymoney, Long totalRepayBaseMoney, Long interest) {
        RecoverRepay recoverRepay = new RecoverRepay();
        recoverRepay.setRepaymentPlanId(plan.getId());
        recoverRepay.setStatus(RecoverRepay.RecoverRepayStatus.UNRECOVER);
        recoverRepay.setCreateTime(new Date());
        recoverRepay.setUpdateTime(new Date());
        recoverRepay.setRecoverRepayMoney(repaymoney);
        recoverRepay.setRecoverRepayBaseMoney(totalRepayBaseMoney);
        recoverRepay.setRecoverRepayInterestMoney(interest);
        recoverRepay.setRepaymentPlanId(plan.getId());
        recoverRepay.setBorrowInfoId(plan.getBorrowInfoId());
        recoverRepay.setBorrowName(plan.getBorrowName());
        recoverRepay.setBorrowUserName(plan.getBorrowUserName());
        recoverRepay.setTotalRepayNum(plan.getTotalRepayNum());
        recoverRepay.setCurRepayNum(plan.getCurRepayNum());
        recoverRepay.setLastRepayDate(plan.getLastRepayDate());
        recoverRepay.setOverduePenalty(plan.getOverduePenalty());
        recoverRepay.setOverdueDate(plan.getOverdueDate());
        // recoverRepay.setRepayTime(plan.getRepayTime());
        recoverRepay.setBorrowUserId(plan.getBorrowUserId());
        recoverRepay.setIsOverDured(plan.getIsOverDured());
        serviceFactory.getPersistService().save(recoverRepay);
    }

    @Override
    public ServiceResult<String> dealRepaymentResult(RepaymentResponseMsg response) {
        ServiceResult<String> result = new ServiceResult<String>();
        if (response == null) {
            result.setIsSuccess(false);
            result.setCode(RespCodeConstants.CommonCode.TRANSMESSAGE_ERRCODE_UNKOWN);
            result.setMessage(RespCodeConstants.CommonCode.TRANSMESSAGE_ERRMSG_NORETURNMSG);
            return result;
        }
        if (!CommonCode.TRANS_SUC.equals(response.getRespCode())) {
            result.setIsSuccess(false);
            result.setCode(response.getRespCode());
            result.setMessage(response.getRespDesc());
            return result;
        }
        if ("recoverRepayment".equals(response.getMerPriv())) {// 偿还垫资操作
            RecoverRepay recover = serviceFactory.getPersistService().get(RecoverRepay.class,
                    Long.parseLong(response.getOrdId()));
            if (recover == null || !recover.getStatus().equals(RecoverRepayStatus.RECOVERING)) {
                result.setIsSuccess(false);
                result.setCode(RespCodeConstants.RepaymentCode.REPAYMENT_NOTFOUND_RECOVER);
                result.setMessage(RespCodeConstants.RepaymentCode.REPAYMENT_NOTFOUND_RECOVER_MSG);
                return result;
            }
            if (recover.getRecoverRepayMoney() != MoneyUtil.convertLongYuanToFen(Double.parseDouble(response
                    .getTransAmt()))) {
                result.setIsSuccess(false);
                result.setCode(RespCodeConstants.RepaymentCode.REPAYMENT_BACKMONEYERROR);
                result.setMessage(RespCodeConstants.RepaymentCode.REPAYMENT_BACKMONEYERROR_MSG);
                return result;
            }
            int i = serviceFactory
                    .getDaoFactory()
                    .getRecoverRepayDao()
                    .updateStatus(Long.parseLong(response.getOrdId()), RecoverRepayStatus.RECOVERED,
                            RecoverRepayStatus.RECOVERING, new Date(), new Date());
            if (i > 0) {
                serviceFactory.getAccountService().changeAccountMoney(recover.getBorrowUserId(),
                        recover.getRecoverRepayMoney(), recover.getRecoverRepayBaseMoney(),
                        recover.getRecoverRepayInterestMoney(), 0l, TransType.PAYBACK, TradeMode.SUBTRACT,
                        recover.getId().toString(),
                        "借款人:" + recover.getBorrowUserName() + "偿还垫资本息|标的:" + recover.getBorrowName());
                // changeAccountMoney(recover.getBorrowUserId(),
                // recover.getRecoverRepayMoney(),
                // recover.getRecoverRepayBaseMoney(),
                // recover.getRecoverRepayInterestMoney(), TransType.PAYBACK,
                // TradeMode.SUBTRACT,
                // recover.getId().toString(),
                // "借款人:" + recover.getBorrowUserName() + "偿还垫资本息|标的:" +
                // recover.getBorrowName());

                BorrowInfo borrowInfo = serviceFactory.getPersistService().get(BorrowInfo.class,
                        recover.getBorrowInfoId());

                serviceFactory.getAccountService().changeAccountMoney(borrowInfo.getGuaranteeUserId(),
                        recover.getRecoverRepayMoney(), 0l, 0l, 0l, TransType.PAYBACK, TradeMode.ADD,
                        recover.getId().toString(),
                        "担保企业" + borrowInfo.getGuaranteeRealName() + "回收垫资本息|标的：" + recover.getBorrowName());
                // changeAccountMoney(borrowInfo.getGuaranteeUserId(),
                // recover.getRecoverRepayMoney(), TransType.PAYBACK,
                // TradeMode.ADD, recover.getId().toString(),
                // "担保企业" + borrowInfo.getGuaranteeRealName() + "回收垫资本息|标的：" +
                // recover.getBorrowName());
                result.setIsSuccess(true);
                result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
                result.setMessage(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
            }
        } else if ("repayment".equals(response.getMerPriv())) {// 还款对账中会用到这段代码
            ReceivePlan receivePlan = serviceFactory.getPersistService().get(ReceivePlan.class,
                    Long.parseLong(response.getOrdId()));
            if (receivePlan == null || !receivePlan.getStatus().equals(ReceiveStatus.RECEIVING)) {
                result.setIsSuccess(false);
                result.setCode(RespCodeConstants.RepaymentCode.REPAYMENT_NOTFOUND_RECOVER);
                result.setMessage(RespCodeConstants.RepaymentCode.REPAYMENT_NOTFOUND_RECOVER_MSG);
                return result;
            }
            BorrowInfo borrowInfo = serviceFactory.getPersistService().get(BorrowInfo.class,
                    receivePlan.getBorrowInfoId());
            if (borrowInfo == null || !borrowInfo.getStatus().equals(BorrowStatus.REPAYMENTING)) {
                result.setIsSuccess(false);
                result.setCode(RespCodeConstants.BorrowInfoCode.BORROWINFO_UNKONW);
                result.setMessage(RespCodeConstants.BorrowInfoCode.BORROWINFO_UNKONW_MSG);
                return result;
            }
            if (receivePlan.getRecMoney() != MoneyUtil.convertLongYuanToFen(Double.parseDouble(response.getTransAmt()))) {
                result.setIsSuccess(false);
                result.setCode(RespCodeConstants.RepaymentCode.REPAYMENT_BACKMONEYERROR);
                result.setMessage(RespCodeConstants.RepaymentCode.REPAYMENT_BACKMONEYERROR_MSG);
                return result;
            }
            int i = serviceFactory
                    .getDaoFactory()
                    .getReceivePlanDao()
                    .updateStatus(receivePlan.getId(), ReceiveStatus.RECEIVED, ReceiveStatus.RECEIVING, new Date(),
                            new Date());
            if (i > 0) {
                serviceFactory.getAccountService().changeAccountMoney(
                        receivePlan.getInvestUserId(),
                        receivePlan.getRecMoney(),
                        0l,
                        0l,
                        0l,
                        TransType.REPAYMENT,
                        TradeMode.ADD,
                        receivePlan.getId().toString(),
                        "还款对账,收回本金[" + receivePlan.getRecBaseMoney() + "],收回利息[" + receivePlan.getRecInterestMoney()
                                + "]" + ",收回附加利息["
                                + (receivePlan.getRecAddMoney() != null ? receivePlan.getRecAddMoney() : 0) + "]");

                // changeAccountMoney(
                // receivePlan.getInvestUserId(),
                // receivePlan.getRecMoney(),
                // TransType.REPAYMENT,
                // TradeMode.ADD,
                // receivePlan.getId().toString(),
                // "还款对账,收回本金[" + receivePlan.getRecBaseMoney() + "],收回利息[" +
                // receivePlan.getRecInterestMoney()
                // + "]" + ",收回附加利息["
                // + (receivePlan.getRecAddMoney() != null ?
                // receivePlan.getRecAddMoney() : 0) + "]");

                // 还款人资金账户变动,资金流水添加 根据实际出账账户和借款人账户是否相同来判断是否是垫资还款交易
                if (!borrowInfo.getBorrowUserTrustAccountId().equals(response.getOutCustId())) {
                    // 担保公司垫资还款,记录担保用户账户资金变动
                    serviceFactory.getAccountService().changeAccountMoney(
                            borrowInfo.getGuaranteeUserId(),
                            receivePlan.getRecMoney(),
                            0l,
                            0l,
                            0l,
                            TransType.ADVANCEREPAY,
                            TradeMode.SUBTRACT,
                            borrowInfo.getId().toString(),
                            "还款对账,担保人垫资本息| 标的:" + borrowInfo.getBorrowName() + ",第" + receivePlan.getCurRecNum()
                                    + "期还款");

                    // changeAccountMoney(
                    // borrowInfo.getGuaranteeUserId(),
                    // receivePlan.getRecMoney(),
                    // TransType.ADVANCEREPAY,
                    // TradeMode.SUBTRACT,
                    // borrowInfo.getId().toString(),
                    // "还款对账,担保人垫资本息| 标的:" + borrowInfo.getBorrowName() + ",第" +
                    // receivePlan.getCurRecNum()
                    // + "期还款");
                } else {
                    // 借款人正常还款
                    serviceFactory.getAccountService().changeAccountMoney(borrowInfo.getBorrowUserId(),
                            receivePlan.getRecMoney(), receivePlan.getRecBaseMoney(),
                            receivePlan.getRecInterestMoney() + receivePlan.getRecAddMoney(), 0l, TransType.REPAYMENT,
                            TradeMode.SUBTRACT, borrowInfo.getId().toString(),
                            "还款对账,融资还款|标的:" + borrowInfo.getBorrowName());
                    //
                    // changeAccountMoney(borrowInfo.getBorrowUserId(),
                    // receivePlan.getRecMoney(), receivePlan.getRecBaseMoney(),
                    // receivePlan.getRecInterestMoney() +
                    // receivePlan.getRecAddMoney(), TransType.REPAYMENT,
                    // TradeMode.SUBTRACT, borrowInfo.getId().toString(),
                    // "还款对账,融资还款|标的:" + borrowInfo.getBorrowName());
                }

                // /**
                // * 判断本期还款计划对应的收款计划是否已经都还清,如果都还清则更新本期还款计划状态为：已还清。
                // */
                // boolean isRepaymentPlanRepaymented =
                // serviceFactory.getRepaymentService()
                // .checkRepaymentPlanIsRepaymented(borrowInfo.getId(),
                // receivePlan.getCurRecNum());
                // if (isRepaymentPlanRepaymented) {
                // int m =
                // serviceFactory.getRepaymentService().updateRepaymentPlanStatus(borrowInfo.getId(),
                // ReplaymentStatus.REPAYMENTED, ReplaymentStatus.SETTLING, new
                // Date(), new Date(),
                // receivePlan.getCurRecNum());
                // if (m > 0) {
                // serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                // receivePlan.getId().toString(), LogType.REPAYMENT_MESSAGE,
                // "还款对账,更新本期还款计划成功，期数[" + receivePlan.getCurRecNum() + "]");
                // } else {
                // serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                // receivePlan.getId().toString(), LogType.REPAYMENT_EXCEPTION,
                // "还款对账,更新本期还款计划失败，期数[" + receivePlan.getCurRecNum() +
                // "],标的ID[" + borrowInfo.getId() + "]");
                // }
                // }
                /**
                 * 判断借款人的所有还款计划是否已经全部还清，若已经全部还清则更新借款标的状态为：已还清。
                 */
                // boolean isBorrowInfoRepaymented =
                // serviceFactory.getRepaymentService().checkBorrowInfoIsRepaymented(
                // borrowInfo.getId());
                // if (isBorrowInfoRepaymented) {
                // // 更新标的状态为已还清
                // int n =
                // serviceFactory.getBorrowService().updateBorroInoStatus(borrowInfo.getId(),
                // BorrowStatus.REPAYMENTED, BorrowStatus.REPAYMENTING, new
                // Date(), new Date());
                // if (n > 0) {
                // serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                // borrowInfo.getId().toString(), LogType.REPAYMENT_MESSAGE,
                // "还款对账,更新标的状态成功");
                // } else {
                // serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                // borrowInfo.getId().toString(), LogType.REPAYMENT_EXCEPTION,
                // "还款对账,更新标的状态失败");
                // }
                //
                // // 同时将该借款标的对应的投资信息记录状态改变为：已回款
                // int j =
                // serviceFactory.getInvestInfoService().updateAllInvestInfoStatus(borrowInfo.getId(),
                // InvestStatus.LOANED, InvestStatus.RETURNED);
                // if (j > 0) {
                // serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                // borrowInfo.getId().toString(), LogType.REPAYMENT_MESSAGE,
                // "还款对账,更新借款标的对应的投资信息记录状态改变为：已回款,成功,更新数量[" + j + "]");
                // } else {
                // serviceFactory.getSystemLogService().addLog(borrowInfo.getId().toString(),
                // borrowInfo.getId().toString(), LogType.REPAYMENT_EXCEPTION,
                // "还款对账,更新借款标的对应的投资信息记录状态改变为：已回款,失败");
                // }
                // }
            }
        }
        return result;
    }

    @Override
    public void packBatchRepayment(RepaymentRequestMsg reqMsg) {
        RepaymentPlan repaymentPlan = serviceFactory.getPersistService().get(RepaymentPlan.class,
                Long.parseLong(reqMsg.getRepaymentPlanId()));
        repaymentPlan.setStatus(ReplaymentStatus.SETTLING);
        if (reqMsg.isPlatfor()) {
            repaymentPlan.setType(ReplaymentType.ADVANCE);
        } else {
            repaymentPlan.setType(ReplaymentType.NORMAL);
        }
        serviceFactory.getPersistService().update(repaymentPlan);
        serviceFactory.getRepaymentService().setReceivePlanBatch(reqMsg.getReceivePlanIds(), reqMsg.getBatchId());
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void setReceivePlanBatch(List<Long> receivePlanIds, String batchId) {
        for (Long id : receivePlanIds) {
            ReceivePlan plan = daoFactory.getReceivePlanDao().get(id);
            plan.setBatchId(batchId);
            plan.setStatus(ReceiveStatus.RECEIVING);
            daoFactory.getReceivePlanDao().update(plan);
        }
    }

    @Override
    public void packRepayment(RepaymentRequestMsg reqMsg) {
        if ("recoverRepayment".equals(reqMsg.getMerPriv())) {
            // 借款人偿还垫资操作
            RecoverRepay recover = serviceFactory.getPersistService().get(RecoverRepay.class,
                    Long.parseLong(reqMsg.getOrdId()));
            recover.setStatus(RecoverRepayStatus.RECOVERING);
            // 设置订单日期
            reqMsg.setOrdDate(DateTimeUtil.formatToStr(recover.getCreateTime(), DateTimeUtil.DATE_FORMAT_YYYYMMDD));
            List<InvestInfo> investInfos = daoFactory.getInvestInfoDao().queryList(reqMsg.getBorrowinfoId(), null);
            InvestInfo investInfo = investInfos.get(0);
            // 设置关联投标id
            reqMsg.setSubOrdId(investInfo.getId().toString());
            reqMsg.setSubOrdDate(DateTimeUtil.formatToStr(investInfo.getCreateTime(), DateTimeUtil.DATE_FORMAT_YYYYMMDD));
            // 设置入款子账户
            Account account = serviceFactory.getAccountService().getAccount(reqMsg.getGuaranteeUserId());
            reqMsg.setInAcctId("");
            if (account != null) {
                reqMsg.setInAcctId(account.getSubAccountId());
            }
            serviceFactory.getPersistService().update(recover);
        }
    }

    @Override
    public void repaymentReconciliation(Integer pageNum, Integer pageSize, Date beginDate, Date endDate) {
        ReconciliationResponseMsg response = serviceFactory.getRepaymentService().doRepaymentReconciliation(pageNum,
                pageSize, beginDate, endDate);
        if (!StringHelper.isEmpty(response.getTotalItems())
                && (pageNum * pageSize) < Integer.parseInt(response.getTotalItems())) {
            repaymentReconciliation(pageNum + 1, pageSize, beginDate, endDate);
        }
    }

    @Override
    public ReconciliationResponseMsg doRepaymentReconciliation(Integer pageNum, Integer pageSize, Date beginDate,
            Date endDate) {
        ReconciliationRequestMsg reqMsg = new ReconciliationRequestMsg();
        reqMsg.setBeginDate(DateTimeUtil.formatToStr(beginDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
        reqMsg.setEndDate(DateTimeUtil.formatToStr(endDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
        reqMsg.setPageNum(pageNum.toString());
        reqMsg.setPageSize(pageSize.toString());
        reqMsg.setQueryTransType("REPAYMENT");
        reqMsg.setPartnerTransType(PartnerTransType.Reconciliation);
        reqMsg.setTransType(TransCodeConstants.PartnerTransCode.REQUEST);
        ReconciliationResponseMsg response = (ReconciliationResponseMsg) serviceFactory.getPartnerService().request(
                reqMsg);
        List<ReconciliationInfo> list = response.getReconciliationDtoList();
        if (list != null && list.size() > 0) {
            // PoolServer poolServer = new PoolServer(50);
            for (ReconciliationInfo dto : list) {
                final RepaymentResponseMsg repaymentResponseMsg = new RepaymentResponseMsg();
                repaymentResponseMsg.setOrdId(dto.getOrdId());
                repaymentResponseMsg.setTransAmt(dto.getTransAmt());
                repaymentResponseMsg.setOutCustId(dto.getBorrCustId());
                if ("I".equals(dto.getTransStat()) || "P".equals(dto.getTransStat())) {
                    if ("I".equals(dto.getTransStat())) {// 失败
                        repaymentResponseMsg.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
                        repaymentResponseMsg.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
                    } else if ("P".equals(dto.getTransStat())) {// 成功
                        repaymentResponseMsg.setRespCode(RespCodeConstants.CommonCode.TRANS_SUC);
                        repaymentResponseMsg.setRespDesc(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                    }
                    RecoverRepay recoverRepay = serviceFactory.getPersistService().get(RecoverRepay.class,
                            Long.parseLong(dto.getOrdId()));
                    if (recoverRepay != null) {
                        repaymentResponseMsg.setMerPriv("recoverRepayment");// 还垫资交易
                    } else {
                        repaymentResponseMsg.setMerPriv("repayment");// 正常还款交易
                    }
                    // poolServer.executeTask(new Runnable() {
                    // public void run() {
                    serviceFactory.getRepaymentService().dealRepaymentResult(repaymentResponseMsg);
                    // }
                    // });
                }
            }
            // poolServer.endServer();
        }
        return response;
    }

    @Override
    public void trfReconciliation(Integer pageNum, Integer pageSize, Date beginDate, Date endDate) {
        TrfReconciliationResponseMsg response = serviceFactory.getRepaymentService().doTrfReconciliation(pageNum,
                pageSize, beginDate, endDate);
        if (!StringHelper.isEmpty(response.getTotalItems())
                && (pageNum * pageSize) < Integer.parseInt(response.getTotalItems())) {
            trfReconciliation(pageNum + 1, pageSize, beginDate, endDate);
        }
    }

    @Override
    public TrfReconciliationResponseMsg doTrfReconciliation(Integer pageNum, Integer pageSize, Date beginDate,
            Date endDate) {
        TrfReconciliationRequestMsg reqMsg = new TrfReconciliationRequestMsg();
        reqMsg.setBeginDate(DateTimeUtil.formatToStr(beginDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
        reqMsg.setEndDate(DateTimeUtil.formatToStr(endDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
        reqMsg.setPageNum(pageNum.toString());
        reqMsg.setPageSize(pageSize.toString());

        reqMsg.setPartnerTransType(PartnerTransType.TrfReconciliation);
        reqMsg.setTransType(TransCodeConstants.PartnerTransCode.REQUEST);
        TrfReconciliationResponseMsg response = (TrfReconciliationResponseMsg) serviceFactory.getPartnerService()
                .request(reqMsg);
        List<TrfReconciliationDto> list = response.getTrfReconciliationDtoList();
        if (list != null && list.size() > 0) {
            PoolServer poolServer = new PoolServer(list.size());
            for (TrfReconciliationDto dto : list) {
                if ("S".equals(dto.getTransStat()) || "F".equals(dto.getTransStat())) {
                    final TransferResponse transferResponse = new TransferResponse();
                    transferResponse.setOrdId(dto.getOrdId());
                    if ("S".equals(dto.getTransStat())) {// 成功
                        transferResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_SUC);
                        transferResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
                    } else if ("F".equals(dto.getTransStat())) {// 失败
                        transferResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
                        transferResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
                    }
                    poolServer.executeTask(new Runnable() {
                        public void run() {
                            serviceFactory.getTransferService().dealTransferResult(transferResponse);
                        }
                    });
                }
            }
            poolServer.endServer();
        }
        return response;
    }
}
